const defAttr = () => ({
    program: null,
    data: {},//在同一个程序集对象中, 所有Unifrom变量值都是相同的,除非在更新前重新更改,否则会后覆盖前
    // 'u_Color': {
    //     value: [1, 1, 1, 1],
    //     type: 'unifroms4fv',
    //     location: null,
    //     needUpdate: true,
    //     cRend : false, //持续渲染
    // }
    mode: [
        "POINTS",
        "TRIANGLES", "TRIANGLE_STRIP", "TRIANGLE_FAN",
        "LINES", "LINE_STRIP", "LINE_LOOP",
    ],
    maps: {},
    // 'u_Sampler': {
    //     image: image,
    //     WRAP_W: gl.CLAMP_TO_EDGE,
    //     WRAP_H: gl.CLAMP_TO_EDGE,
    //     MIN_FILTER = gl.LINEAR,
    //     MAG_FILTER = null,
    //     format = gl.RGB,
    //     flipY = 1,
    //     location: null,
    //     needUpdate: true,
    // }
})

//材质对象
export default class Mat {
    constructor(attr) {
        Object.assign(this, defAttr(), attr);
    }

    init(gl) {
        const { program, data, maps } = this

        Object.entries(data).forEach(([key, val], index) => {
            let location = gl.getUniformLocation(program, key);
            val.location = location;
            val.needUpdate = true;
        });
        Object.entries(maps).forEach(([key, val], index) => {
            let location = gl.getUniformLocation(program, key);
            val.location = location;
            val.needUpdate = true;
            val.buffer = gl.createTexture();
        });
    }

    update(gl) {
        this._updateData(gl);
        this._updateMaps(gl);
    }

    _updateData(gl) {
        const { data } = this;
        Object.entries(data).forEach(([key, val], index) => {
            const { needUpdate, value, type, location, cRend } = val;
            if (needUpdate || cRend) {
                if (type.indexOf('Matrix') == -1) {
                    gl[type](location, value);
                } else {
                    gl[type](location, false, value);
                }

                val.needUpdate = false;
            }
        });
    }

    _updateMaps(gl) {
        const { maps, program } = this;
        Object.entries(maps).forEach(([key, value], index) => {
            gl.bindTexture(gl.TEXTURE_2D, value.buffer);
            if (!value.needUpdate) {
                return;
            }
            value.needUpdate = false;
            const {
                image,
                WRAP_H,
                WRAP_W,
                MIN_FILTER = gl.LINEAR,
                MAG_FILTER,
                format = gl.RGB,
                flipY = 1,
            } = value;

            //是否反转Y轴
            flipY && gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);

            // 激活纹理单元
            gl.activeTexture(gl[`TEXTURE${index}`]);

            gl.texImage2D(
                gl.TEXTURE_2D,
                0,
                format,
                format,
                gl.UNSIGNED_BYTE,
                image
            );

            //设置非二次幂图片(非二次幂图片只有在边缘加紧时才可以显示)
            WRAP_H && gl.texParameteri(
                gl.TEXTURE_2D,//二维纹理
                gl.TEXTURE_WRAP_T,//纹理容器在t方向的尺寸
                gl.CLAMP_TO_EDGE//边缘加紧的意思
            );
            WRAP_W && gl.texParameteri(
                gl.TEXTURE_2D,//二维纹理
                gl.TEXTURE_WRAP_S,//纹理容器在s方向的尺寸
                gl.CLAMP_TO_EDGE//边缘加紧的意思
            );

            MAG_FILTER && gl.texParameteri(
                gl.TEXTURE_2D,//二维纹理
                gl.TEXTURE_MAG_FILTER,//纹理缩小滤波器(当图片源比显示框大的时候进行等比缩小)
                gl.MAG_FILTER//线性
            );

            if (!MIN_FILTER || MIN_FILTER > 9729) {
                gl.generateMipmap(gl.TEXTURE_2D)
            }

            MIN_FILTER && gl.texParameteri(
                gl.TEXTURE_2D,
                gl.TEXTURE_MIN_FILTER,
                MIN_FILTER
            )

            const u_Sampler = gl.getUniformLocation(program, key);
            gl.uniform1i(u_Sampler, index);//gl.TEXTURE0激活的是0
        });
    }

    setData(key, value) {
        const { data } = this;
        if (!data[key]) {
            return;
        }

        data[key].needUpdate = true;
        Object.assign(data[key], value);
    }

    setMap(key, value) {
        const { maps } = this;
        let map = maps[key];
        if (!map)
            return;
        map.needUpdate = true;
        Object.assign(map, value);
    }

    clone() {
        const { program, mode, data, maps } = this;

        let curData = {};
        Object.entries(data).forEach(([key, val], index) => {
            curData[key] = {
                type: val.type.slice(),
            };
            if (val.type.lastIndexOf('v') == val.type.length - 1) {
                curData[key].value = val.value.concat();
            } else {
                curData[key].value = val.value;
            }
        })

        let curMap = {};
        Object.entries(maps).forEach(([key, val], index) => {
            curMap[key] = {
                image: val.image,
                WRAP_W: val.WRAP_W,
                WRAP_H: val.WRAP_H,
                MIN_FILTER: val.MIN_FILTER,
                MAG_FILTER: val.MAG_FILTER,
                format: val.format,
                flipY: val.flipY,
            };
        })

        var a = new Mat({
            program: program,
            mode: mode.concat(),
            data: curData,
            maps: curMap,
        });

        return new Mat({
            program: program,
            mode: mode.concat(),
            data: curData,
            maps: curMap,
        });
    }

}